Avoid recreating pangolayouts in GtkTextView on cursor movement (#435405,
authorYevgen Muntyan <muntyan@tamu.edu>
Fri, 1 Jun 2007 06:25:43 +0000 (06:25 +0000)
committerYevgen Muntyan <muntyan@src.gnome.org>
Fri, 1 Jun 2007 06:25:43 +0000 (06:25 +0000)
2007-06-01  Yevgen Muntyan  <muntyan@tamu.edu>

Avoid recreating pangolayouts in GtkTextView on cursor movement
(#435405, Behdad Esfahbod).

* gtk/gtktextlayout.c:
* gtk/gtktextlayout.h: new GtkTextLayout method invalidate_cursors(),
and functions gtk_text_layout_invalidate_cursors() and
gtk_text_layout_cursors_changed(), to use when invalidation is due
to moved marks or changed selection.

* gtk/gtktextbtree.c:
* gtk/gtktextbtree.h: use what's appropriate when invalidating layout.

* gtk/gtk.symbols: add new functions.

* README.in: added a note about changed GtkTextLayout API.

svn path=/trunk/; revision=18000

ChangeLog
README.in
gtk/gtk.symbols
gtk/gtktextbtree.c
gtk/gtktextbtree.h
gtk/gtktextlayout.c
gtk/gtktextlayout.h

index c5d98c9e523c61b3a6b4a66c2d073d690e84fc5d..088009f29acfb7b8cc27d56c5b7285a19351cf4d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2007-06-01  Yevgen Muntyan  <muntyan@tamu.edu>
+
+       Avoid recreating pangolayouts in GtkTextView on cursor movement
+       (#435405, Behdad Esfahbod).
+
+       * gtk/gtktextlayout.c:
+       * gtk/gtktextlayout.h: new GtkTextLayout method invalidate_cursors(),
+       and functions gtk_text_layout_invalidate_cursors() and
+       gtk_text_layout_cursors_changed(), to use when invalidation is due
+       to moved marks or changed selection.
+
+       * gtk/gtktextbtree.c:
+       * gtk/gtktextbtree.h: use what's appropriate when invalidating layout.
+
+       * gtk/gtk.symbols: add new functions.
+
+       * README.in: added a note about changed GtkTextLayout API.
+
 2007-06-01  Alp Toker  <alp.toker@collabora.co.uk>
 
        * gdk/gdkcairo.c (gdk_cairo_set_source_pixmap): Fix doc typos.
index 3dc5ef8f8b70992f06d3772337c3b204c8c04ef6..ff62e5efe919df48a6d1f03b9a9563c089c76258 100644 (file)
--- a/README.in
+++ b/README.in
@@ -48,6 +48,16 @@ Release notes for 2.12
   GDK for drawing decorations. In particular, metacity <= 2.18.0 is affected
   by this. The problem has been fixed in metacity 2.18.1.
 
+* Semi-private GtkTextLayout api has changed: new GtkTextLayout method
+  invalidate_cursors(), and new functions gtk_text_layout_invalidate_cursors()
+  and gtk_text_layout_cursors_changed(), which should be used in place of
+  gtk_text_layout_invalidate() and gtk_text_layout_changed() if invalidation
+  is due to marks moved or changed selection; new GtkTextLineDisplay structure
+  member. Source compatibility is preserved; binary compatibility may break
+  only if GtkTextLineDisplay structure was created on stack or as a part
+  of another structure (in particular GnomeCanvas and its clones do not need
+  recompiling).
+
 Release notes for 2.10
 ======================
 
index 5b28f131856efe19235177d7e1a2ffdcb28c6e01..2c7963580dabaac00daadde2beef88aae6e227c9 100644 (file)
@@ -3715,6 +3715,7 @@ gtk_text_iter_toggles_tag
 #if IN_HEADER(__GTK_TEXT_LAYOUT_H__)
 #if IN_FILE(__GTK_TEXT_LAYOUT_C__)
 gtk_text_layout_changed
+gtk_text_layout_cursors_changed
 gtk_text_layout_clamp_iter_to_vrange
 gtk_text_layout_default_style_changed
 gtk_text_layout_free_line_data
@@ -3733,6 +3734,7 @@ gtk_text_layout_get_line_yrange
 gtk_text_layout_get_size
 gtk_text_layout_get_type G_GNUC_CONST
 gtk_text_layout_invalidate
+gtk_text_layout_invalidate_cursors
 gtk_text_layout_is_valid
 gtk_text_layout_iter_starts_line
 gtk_text_layout_move_iter_to_line_end
index 93f6b4b3d98fe0d36411a9ce1173716f87fe7652..111bd48ff4e4409ee06c7eabed710b8607b7568e 100644 (file)
@@ -340,7 +340,8 @@ static void            gtk_text_btree_remove_tag_info       (GtkTextBTree   *tre
 
 static void redisplay_region (GtkTextBTree      *tree,
                               const GtkTextIter *start,
-                              const GtkTextIter *end);
+                              const GtkTextIter *end,
+                              gboolean           cursors_only);
 
 /* Inline thingies */
 
@@ -663,7 +664,7 @@ gtk_text_btree_resolve_bidi (GtkTextIter *start,
      */
     line = _gtk_text_line_previous (line);
     _gtk_text_btree_get_iter_at_line (tree, &end_propagate, line, 0);
-    _gtk_text_btree_invalidate_region (tree, end, &end_propagate);
+    _gtk_text_btree_invalidate_region (tree, end, &end_propagate, FALSE);
   }
   
   /* Sweep backward */
@@ -719,7 +720,7 @@ gtk_text_btree_resolve_bidi (GtkTextIter *start,
     if (line && line->dir_propagated_forward == PANGO_DIRECTION_NEUTRAL)
       {
         _gtk_text_btree_get_iter_at_line (tree, &start_propagate, line, 0);
-        _gtk_text_btree_invalidate_region(tree, &start_propagate, start);
+        _gtk_text_btree_invalidate_region (tree, &start_propagate, start, FALSE);
       }
   }
 }
@@ -756,7 +757,7 @@ _gtk_text_btree_delete (GtkTextIter *start,
   
   /* Broadcast the need for redisplay before we break the iterators */
   DV (g_print ("invalidating due to deleting some text (%s)\n", G_STRLOC));
-  _gtk_text_btree_invalidate_region (tree, start, end);
+  _gtk_text_btree_invalidate_region (tree, start, end, FALSE);
 
   /* Save the byte offset so we can reset the iterators */
   start_byte_offset = gtk_text_iter_get_line_index (start);
@@ -1241,8 +1242,7 @@ _gtk_text_btree_insert (GtkTextIter *iter,
     gtk_text_iter_forward_chars (&end, char_count_delta);
 
     DV (g_print ("invalidating due to inserting some text (%s)\n", G_STRLOC));
-    _gtk_text_btree_invalidate_region (tree,
-                                      &start, &end);
+    _gtk_text_btree_invalidate_region (tree, &start, &end, FALSE);
 
 
     /* Convenience for the user */
@@ -1292,7 +1292,7 @@ insert_pixbuf_or_widget_segment (GtkTextIter        *iter,
   gtk_text_iter_forward_char (iter); /* skip forward past the segment */
 
   DV (g_print ("invalidating due to inserting pixbuf/widget (%s)\n", G_STRLOC));
-  _gtk_text_btree_invalidate_region (tree, &start, iter);
+  _gtk_text_btree_invalidate_region (tree, &start, iter, FALSE);
 }
      
 void
@@ -1627,7 +1627,8 @@ _gtk_text_btree_remove_view (GtkTextBTree *tree,
 void
 _gtk_text_btree_invalidate_region (GtkTextBTree      *tree,
                                    const GtkTextIter *start,
-                                   const GtkTextIter *end)
+                                   const GtkTextIter *end,
+                                   gboolean           cursors_only)
 {
   BTreeView *view;
 
@@ -1635,7 +1636,10 @@ _gtk_text_btree_invalidate_region (GtkTextBTree      *tree,
 
   while (view != NULL)
     {
-      gtk_text_layout_invalidate (view->layout, start, end);
+      if (cursors_only)
+       gtk_text_layout_invalidate_cursors (view->layout, start, end);
+      else
+       gtk_text_layout_invalidate (view->layout, start, end);
 
       view = view->next;
     }
@@ -1740,12 +1744,12 @@ queue_tag_redisplay (GtkTextBTree      *tree,
   if (_gtk_text_tag_affects_size (tag))
     {
       DV (g_print ("invalidating due to size-affecting tag (%s)\n", G_STRLOC));
-      _gtk_text_btree_invalidate_region (tree, start, end);
+      _gtk_text_btree_invalidate_region (tree, start, end, FALSE);
     }
   else if (_gtk_text_tag_affects_nonsize_appearance (tag))
     {
       /* We only need to queue a redraw, not a relayout */
-      redisplay_region (tree, start, end);
+      redisplay_region (tree, start, end, FALSE);
     }
 
   /* We don't need to do anything if the tag doesn't affect display */
@@ -2599,7 +2603,8 @@ _gtk_text_btree_char_is_invisible (const GtkTextIter *iter)
 static void
 redisplay_region (GtkTextBTree      *tree,
                   const GtkTextIter *start,
-                  const GtkTextIter *end)
+                  const GtkTextIter *end,
+                  gboolean           cursors_only)
 {
   BTreeView *view;
   GtkTextLine *start_line, *end_line;
@@ -2631,9 +2636,14 @@ redisplay_region (GtkTextBTree      *tree,
       if (ld)
         end_y += ld->height;
 
-      gtk_text_layout_changed (view->layout, start_y,
-                               end_y - start_y,
-                               end_y - start_y);
+      if (cursors_only)
+       gtk_text_layout_cursors_changed (view->layout, start_y,
+                                        end_y - start_y,
+                                         end_y - start_y);
+      else
+       gtk_text_layout_changed (view->layout, start_y,
+                                end_y - start_y,
+                                end_y - start_y);
 
       view = view->next;
     }
@@ -2653,8 +2663,7 @@ redisplay_mark (GtkTextLineSegment *mark)
   gtk_text_iter_forward_char (&end);
 
   DV (g_print ("invalidating due to moving visible mark (%s)\n", G_STRLOC));
-  _gtk_text_btree_invalidate_region (mark->body.mark.tree,
-                                    &iter, &end);
+  _gtk_text_btree_invalidate_region (mark->body.mark.tree, &iter, &end, TRUE);
 }
 
 static void
@@ -2729,7 +2738,7 @@ real_set_mark (GtkTextBTree      *tree,
 
           _gtk_text_btree_get_iter_at_mark (tree, &old_pos,
                                            mark->body.mark.obj);
-          redisplay_region (tree, &old_pos, where);
+          redisplay_region (tree, &old_pos, where, TRUE);
         }
 
       /*
@@ -2863,18 +2872,28 @@ _gtk_text_btree_select_range (GtkTextBTree      *tree,
                              const GtkTextIter *ins,
                               const GtkTextIter *bound)
 {
-  GtkTextIter start, end;
+  GtkTextIter old_ins, old_bound;
 
-  if (_gtk_text_btree_get_selection_bounds (tree, &start, &end))
-    redisplay_region (tree, &start, &end);
+  _gtk_text_btree_get_iter_at_mark (tree, &old_ins,
+                                    tree->insert_mark);
+  _gtk_text_btree_get_iter_at_mark (tree, &old_bound,
+                                    tree->selection_bound_mark);
 
-  /* Move insert AND selection_bound before we redisplay */
-  real_set_mark (tree, tree->insert_mark,
-                 "insert", FALSE, ins, TRUE, FALSE);
-  real_set_mark (tree, tree->selection_bound_mark,
-                 "selection_bound", FALSE, bound, TRUE, FALSE);
+  /* Check if it's no-op since gtk_text_buffer_place_cursor()
+   * also calls this, and this will redraw the cursor line. */
+  if (!gtk_text_iter_equal (&old_ins, ins) ||
+      !gtk_text_iter_equal (&old_bound, bound))
+    {
+      redisplay_region (tree, &old_ins, &old_bound, TRUE);
+
+      /* Move insert AND selection_bound before we redisplay */
+      real_set_mark (tree, tree->insert_mark,
+                    "insert", FALSE, ins, TRUE, FALSE);
+      real_set_mark (tree, tree->selection_bound_mark,
+                    "selection_bound", FALSE, bound, TRUE, FALSE);
 
-  redisplay_region (tree, ins, bound);
+      redisplay_region (tree, ins, bound, TRUE);
+    }
 }
 
 
@@ -5619,8 +5638,7 @@ tag_changed_cb (GtkTextTagTable *table,
           /* Must be a last toggle if there was a first one. */
           _gtk_text_btree_get_iter_at_last_toggle (tree, &end, tag);
           DV (g_print ("invalidating due to tag change (%s)\n", G_STRLOC));
-          _gtk_text_btree_invalidate_region (tree,
-                                            &start, &end);
+          _gtk_text_btree_invalidate_region (tree, &start, &end, FALSE);
 
         }
     }
index 2b2d17cba141dd828ae3d8fe8815d68285dfd60a..053d9e1a20ee1e4a1dc1a729846f064001816dc1 100644 (file)
@@ -92,7 +92,8 @@ void         _gtk_text_btree_remove_view       (GtkTextBTree      *tree,
                                                 gpointer           view_id);
 void         _gtk_text_btree_invalidate_region (GtkTextBTree      *tree,
                                                 const GtkTextIter *start,
-                                                const GtkTextIter *end);
+                                                const GtkTextIter *end,
+                                                gboolean           cursors_only);
 void         _gtk_text_btree_get_view_size     (GtkTextBTree      *tree,
                                                 gpointer           view_id,
                                                 gint              *width,
index 553434a0765945cbac0a79ae91d7b31d6f8fd3ef..2cb2981f7e4f398182f7e346e1aeaeae21867311 100644 (file)
@@ -110,9 +110,14 @@ static void gtk_text_layout_invalidated     (GtkTextLayout     *layout);
 static void gtk_text_layout_real_invalidate        (GtkTextLayout     *layout,
                                                    const GtkTextIter *start,
                                                    const GtkTextIter *end);
+static void gtk_text_layout_real_invalidate_cursors(GtkTextLayout     *layout,
+                                                   const GtkTextIter *start,
+                                                   const GtkTextIter *end);
 static void gtk_text_layout_invalidate_cache       (GtkTextLayout     *layout,
-                                                   GtkTextLine       *line);
-static void gtk_text_layout_invalidate_cursor_line (GtkTextLayout     *layout);
+                                                   GtkTextLine       *line,
+                                                   gboolean           cursors_only);
+static void gtk_text_layout_invalidate_cursor_line (GtkTextLayout     *layout,
+                                                   gboolean           cursors_only);
 static void gtk_text_layout_real_free_line_data    (GtkTextLayout     *layout,
                                                    GtkTextLine       *line,
                                                    GtkTextLineData   *line_data);
@@ -172,6 +177,7 @@ gtk_text_layout_class_init (GtkTextLayoutClass *klass)
 
   klass->wrap = gtk_text_layout_real_wrap;
   klass->invalidate = gtk_text_layout_real_invalidate;
+  klass->invalidate_cursors = gtk_text_layout_real_invalidate_cursors;
   klass->free_line_data = gtk_text_layout_real_free_line_data;
 
   signals[INVALIDATED] =
@@ -411,7 +417,7 @@ gtk_text_layout_set_cursor_direction (GtkTextLayout   *layout,
   if (direction != layout->cursor_direction)
     {
       layout->cursor_direction = direction;
-      gtk_text_layout_invalidate_cursor_line (layout);
+      gtk_text_layout_invalidate_cursor_line (layout, TRUE);
     }
 }
 
@@ -430,7 +436,7 @@ gtk_text_layout_set_keyboard_direction (GtkTextLayout   *layout,
   if (keyboard_dir != layout->keyboard_direction)
     {
       layout->keyboard_direction = keyboard_dir;
-      gtk_text_layout_invalidate_cursor_line (layout);
+      gtk_text_layout_invalidate_cursor_line (layout, TRUE);
     }
 }
 
@@ -498,7 +504,7 @@ gtk_text_layout_set_cursor_visible (GtkTextLayout *layout,
       gtk_text_layout_get_line_yrange (layout, &iter, &y, &height);
       gtk_text_layout_emit_changed (layout, y, height, height);
 
-      gtk_text_layout_invalidate_cache (layout, _gtk_text_iter_get_text_line (&iter));
+      gtk_text_layout_invalidate_cache (layout, _gtk_text_iter_get_text_line (&iter), TRUE);
     }
 }
 
@@ -560,7 +566,7 @@ gtk_text_layout_set_preedit_string (GtkTextLayout *layout,
       layout->preedit_cursor = 0;
     }
 
-  gtk_text_layout_invalidate_cursor_line (layout);
+  gtk_text_layout_invalidate_cursor_line (layout, FALSE);
 }
 
 void
@@ -592,11 +598,12 @@ gtk_text_layout_emit_changed (GtkTextLayout *layout,
   g_signal_emit (layout, signals[CHANGED], 0, y, old_height, new_height);
 }
 
-void
-gtk_text_layout_changed (GtkTextLayout *layout,
-                         gint           y,
-                         gint           old_height,
-                         gint           new_height)
+static void
+text_layout_changed (GtkTextLayout *layout,
+                     gint           y,
+                     gint           old_height,
+                     gint           new_height,
+                     gboolean       cursors_only)
 {
   /* Check if the range intersects our cached line display,
    * and invalidate the cached line if so.
@@ -609,12 +616,30 @@ gtk_text_layout_changed (GtkTextLayout *layout,
       gint cache_height = layout->one_display_cache->height;
 
       if (cache_y + cache_height > y && cache_y < y + old_height)
-       gtk_text_layout_invalidate_cache (layout, line);
+       gtk_text_layout_invalidate_cache (layout, line, cursors_only);
     }
-  
+
   gtk_text_layout_emit_changed (layout, y, old_height, new_height);
 }
 
+void
+gtk_text_layout_changed (GtkTextLayout *layout,
+                         gint           y,
+                         gint           old_height,
+                         gint           new_height)
+{
+  text_layout_changed (layout, y, old_height, new_height, FALSE);
+}
+
+void
+gtk_text_layout_cursors_changed (GtkTextLayout *layout,
+                                 gint           y,
+                                gint           old_height,
+                                gint           new_height)
+{
+  text_layout_changed (layout, y, old_height, new_height, TRUE);
+}
+
 void
 gtk_text_layout_free_line_data (GtkTextLayout     *layout,
                                 GtkTextLine       *line,
@@ -633,6 +658,15 @@ gtk_text_layout_invalidate (GtkTextLayout *layout,
     (layout, start_index, end_index);
 }
 
+void
+gtk_text_layout_invalidate_cursors (GtkTextLayout *layout,
+                                   const GtkTextIter *start_index,
+                                   const GtkTextIter *end_index)
+{
+  (* GTK_TEXT_LAYOUT_GET_CLASS (layout)->invalidate_cursors)
+    (layout, start_index, end_index);
+}
+
 GtkTextLineData*
 gtk_text_layout_wrap (GtkTextLayout *layout,
                       GtkTextLine  *line,
@@ -748,20 +782,33 @@ gtk_text_layout_invalidate_all (GtkTextLayout *layout)
 
 static void
 gtk_text_layout_invalidate_cache (GtkTextLayout *layout,
-                                  GtkTextLine   *line)
+                                  GtkTextLine   *line,
+                                 gboolean       cursors_only)
 {
   if (layout->one_display_cache && line == layout->one_display_cache->line)
     {
-      GtkTextLineDisplay *tmp_display = layout->one_display_cache;
-      layout->one_display_cache = NULL;
-      gtk_text_layout_free_line_display (layout, tmp_display);
+      GtkTextLineDisplay *display = layout->one_display_cache;
+
+      if (cursors_only)
+       {
+         g_slist_foreach (display->cursors, (GFunc)g_free, NULL);
+         g_slist_free (display->cursors);
+         display->cursors = NULL;
+         display->cursors_invalid = TRUE;
+       }
+      else
+       {
+         layout->one_display_cache = NULL;
+         gtk_text_layout_free_line_display (layout, display);
+       }
     }
 }
 
 /* Now invalidate the paragraph containing the cursor
  */
 static void
-gtk_text_layout_invalidate_cursor_line (GtkTextLayout *layout)
+gtk_text_layout_invalidate_cursor_line (GtkTextLayout *layout,
+                                       gboolean cursors_only)
 {
   GtkTextLayoutPrivate *priv = GTK_TEXT_LAYOUT_GET_PRIVATE (layout);
   GtkTextLineData *line_data;
@@ -772,8 +819,14 @@ gtk_text_layout_invalidate_cursor_line (GtkTextLayout *layout)
   line_data = _gtk_text_line_get_data (priv->cursor_line, layout);
   if (line_data)
     {
-      gtk_text_layout_invalidate_cache (layout, priv->cursor_line);
-      _gtk_text_line_invalidate_wrap (priv->cursor_line, line_data);
+      if (cursors_only)
+         gtk_text_layout_invalidate_cache (layout, priv->cursor_line, TRUE);
+      else
+       {
+         gtk_text_layout_invalidate_cache (layout, priv->cursor_line, FALSE);
+         _gtk_text_line_invalidate_wrap (priv->cursor_line, line_data);
+       }
+
       gtk_text_layout_invalidated (layout);
     }
 }
@@ -820,7 +873,7 @@ gtk_text_layout_real_invalidate (GtkTextLayout *layout,
     {
       GtkTextLineData *line_data = _gtk_text_line_get_data (line, layout);
 
-      gtk_text_layout_invalidate_cache (layout, line);
+      gtk_text_layout_invalidate_cache (layout, line, FALSE);
       
       if (line_data)
         _gtk_text_line_invalidate_wrap (line, line_data);
@@ -834,12 +887,48 @@ gtk_text_layout_real_invalidate (GtkTextLayout *layout,
   gtk_text_layout_invalidated (layout);
 }
 
+static void
+gtk_text_layout_real_invalidate_cursors (GtkTextLayout     *layout,
+                                        const GtkTextIter *start,
+                                        const GtkTextIter *end)
+{
+  /* Check if the range intersects our cached line display,
+   * and invalidate the cached line if so.
+   */
+  if (layout->one_display_cache)
+    {
+      GtkTextIter line_start, line_end;
+      GtkTextLine *line = layout->one_display_cache->line;
+
+      _gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
+                                        &line_start, line, 0);
+      line_end = line_start;
+      if (!gtk_text_iter_ends_line (&line_end))
+       gtk_text_iter_forward_to_line_end (&line_end);
+
+      if (gtk_text_iter_compare (start, end) > 0)
+       {
+         const GtkTextIter *tmp = start;
+         start = end;
+         end = tmp;
+       }
+
+      if (gtk_text_iter_compare (&line_start, end) <= 0 &&
+         gtk_text_iter_compare (start, &line_end) <= 0)
+       {
+         gtk_text_layout_invalidate_cache (layout, line, TRUE);
+       }
+    }
+
+  gtk_text_layout_invalidated (layout);
+}
+
 static void
 gtk_text_layout_real_free_line_data (GtkTextLayout     *layout,
                                      GtkTextLine       *line,
                                      GtkTextLineData   *line_data)
 {
-  gtk_text_layout_invalidate_cache (layout, line);
+  gtk_text_layout_invalidate_cache (layout, line, FALSE);
 
   g_free (line_data);
 }
@@ -1789,6 +1878,112 @@ add_preedit_attrs (GtkTextLayout     *layout,
   pango_attr_iterator_destroy (iter);
 }
 
+/* Iterate over the line and fill in display->cursors.
+ * It's a stripped copy of gtk_text_layout_get_line_display() */
+static void
+update_text_display_cursors (GtkTextLayout      *layout,
+                            GtkTextLine        *line,
+                            GtkTextLineDisplay *display)
+{
+  GtkTextLineSegment *seg;
+  GtkTextIter iter;
+  gint layout_byte_offset, buffer_byte_offset;
+  GSList *cursor_byte_offsets = NULL;
+  GSList *cursor_segs = NULL;
+  GSList *tmp_list1, *tmp_list2;
+
+  if (!display->cursors_invalid)
+    return;
+
+  display->cursors_invalid = FALSE;
+
+  _gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
+                                    &iter, line, 0);
+
+  /* Special-case optimization for completely
+   * invisible lines; makes it faster to deal
+   * with sequences of invisible lines.
+   */
+  if (totally_invisible_line (layout, line, &iter))
+    return;
+
+  /* Iterate over segments */
+  layout_byte_offset = 0; /* position in the layout text (includes preedit, does not include invisible text) */
+  buffer_byte_offset = 0; /* position in the buffer line */
+  seg = _gtk_text_iter_get_any_segment (&iter);
+  while (seg != NULL)
+    {
+      /* Displayable segments */
+      if (seg->type == &gtk_text_char_type ||
+          seg->type == &gtk_text_pixbuf_type ||
+          seg->type == &gtk_text_child_type)
+        {
+          _gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
+                                            &iter, line,
+                                            buffer_byte_offset);
+
+         if (!_gtk_text_btree_char_is_invisible (&iter))
+            layout_byte_offset += seg->byte_count;
+
+         buffer_byte_offset += seg->byte_count;
+        }
+
+      /* Marks */
+      else if (seg->type == &gtk_text_right_mark_type ||
+               seg->type == &gtk_text_left_mark_type)
+        {
+         gint cursor_offset = 0;
+
+         /* At the insertion point, add the preedit string, if any */
+
+         if (_gtk_text_btree_mark_is_insert (_gtk_text_buffer_get_btree (layout->buffer),
+                                             seg->body.mark.obj))
+           {
+             display->insert_index = layout_byte_offset;
+
+             if (layout->preedit_len > 0)
+               {
+                 layout_byte_offset += layout->preedit_len;
+                  /* DO NOT increment the buffer byte offset for preedit */
+                 cursor_offset = layout->preedit_cursor - layout->preedit_len;
+               }
+           }
+
+          /* Display visible marks */
+
+          if (seg->body.mark.visible)
+            {
+              cursor_byte_offsets = g_slist_prepend (cursor_byte_offsets,
+                                                     GINT_TO_POINTER (layout_byte_offset + cursor_offset));
+              cursor_segs = g_slist_prepend (cursor_segs, seg);
+            }
+        }
+
+      /* Toggles */
+      else if (seg->type == &gtk_text_toggle_on_type ||
+               seg->type == &gtk_text_toggle_off_type)
+        {
+        }
+
+      else
+        g_error ("Unknown segment type: %s", seg->type->name);
+
+      seg = seg->next;
+    }
+
+  tmp_list1 = cursor_byte_offsets;
+  tmp_list2 = cursor_segs;
+  while (tmp_list1)
+    {
+      add_cursor (layout, display, tmp_list2->data,
+                  GPOINTER_TO_INT (tmp_list1->data));
+      tmp_list1 = tmp_list1->next;
+      tmp_list2 = tmp_list2->next;
+    }
+  g_slist_free (cursor_byte_offsets);
+  g_slist_free (cursor_segs);
+}
+
 GtkTextLineDisplay *
 gtk_text_layout_get_line_display (GtkTextLayout *layout,
                                   GtkTextLine   *line,
@@ -1816,7 +2011,11 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
     {
       if (line == layout->one_display_cache->line &&
           (size_only || !layout->one_display_cache->size_only))
-        return layout->one_display_cache;
+       {
+         if (!size_only)
+            update_text_display_cursors (layout, line, layout->one_display_cache);
+         return layout->one_display_cache;
+       }
       else
         {
           GtkTextLineDisplay *tmp_display = layout->one_display_cache;
@@ -1825,6 +2024,8 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
         }
     }
 
+  DV (g_print ("creating one line display cache (%s)\n", G_STRLOC));
+
   display = g_new0 (GtkTextLineDisplay, 1);
 
   display->size_only = size_only;
index 21e3d53e124701f1c030093ded40c0406cd6721a..ffc889f7113e769b8e945b80bd9f39455ca95ceb 100644 (file)
@@ -209,11 +209,14 @@ struct _GtkTextLayoutClass
                                  gint               x,
                                  gint               y);
 
+  void (*invalidate_cursors)    (GtkTextLayout     *layout,
+                                 const GtkTextIter *start,
+                                 const GtkTextIter *end);
+
   /* Padding for future expansion */
   void (*_gtk_reserved1) (void);
   void (*_gtk_reserved2) (void);
   void (*_gtk_reserved3) (void);
-  void (*_gtk_reserved4) (void);
 };
 
 struct _GtkTextAttrAppearance
@@ -254,6 +257,8 @@ struct _GtkTextLineDisplay
   GtkTextLine *line;
   
   GdkColor *pg_bg_color;
+
+  guint cursors_invalid : 1;
 };
 
 extern PangoAttrType gtk_text_attr_appearance_type;
@@ -327,6 +332,9 @@ void gtk_text_layout_get_iter_at_position (GtkTextLayout     *layout,
 void gtk_text_layout_invalidate        (GtkTextLayout     *layout,
                                         const GtkTextIter *start,
                                         const GtkTextIter *end);
+void gtk_text_layout_invalidate_cursors(GtkTextLayout     *layout,
+                                        const GtkTextIter *start,
+                                        const GtkTextIter *end);
 void gtk_text_layout_free_line_data    (GtkTextLayout     *layout,
                                         GtkTextLine       *line,
                                         GtkTextLineData   *line_data);
@@ -353,6 +361,10 @@ void     gtk_text_layout_changed              (GtkTextLayout     *layout,
                                                gint               y,
                                                gint               old_height,
                                                gint               new_height);
+void     gtk_text_layout_cursors_changed      (GtkTextLayout     *layout,
+                                               gint               y,
+                                               gint               old_height,
+                                               gint               new_height);
 void     gtk_text_layout_get_iter_location    (GtkTextLayout     *layout,
                                                const GtkTextIter *iter,
                                                GdkRectangle      *rect);